﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Blockmania.Classes;


namespace Blockmania.Classes
{
    class Mootor
    {
        // Constants
        public const int ekraani_laius = 800;
        public const int ekraani_korgus = 600;

        // Mängulaua ülemise vasaku nurga positsioon
        public static readonly Vector2 laua_ylemine_vasak_vektor = new Vector2(275f, 30f);

        // Järgmise klotsi ülemise vasaku nurga positsioon
        public static readonly Vector2 jargmise_klotsi_vektor = new Vector2(629f, 86f);

        // Skooritabeli keskpunk. Kasutame, et numbreid keskel kuvada
        private static readonly Vector2 LEVEL_BOX_CENTER = new Vector2(91f, 452f);
        private static readonly Vector2 LINES_BOX_CENTER = new Vector2(182f, 452f);
        private static readonly Vector2 SCORE_BOX_CENTER = new Vector2(137f, 540f);

        // Mängu olekud
        private bool gameOver;
        private bool gamePause;
        private bool newGame;

        // Skoori süsteem
        public const int LINES_FOR_NEXT_LEVEL = 10;
        private int gameLines;
        private int gameScore;
        private int gameLevel;


        // Aja muutujad
        public const float INITIAL_TIMER_MAX = 0.5f;
        public const float TIMER_DECREMENT = 0.2f;
        public const int LAST_LEVEL_FOR_TIMER_DECREMENT = 9;
        private float timer;
        private float timerMax;


        #region Properties

        public bool GameOver
        {
            get { return gameOver; }
            set { gameOver = value; }
        }

        public bool GamePause
        {
            get { return gamePause; }
            set { gamePause = value; }
        }

        public bool Newgame
        {
            get { return newGame; }
            set { newGame = value; }
        }
        #endregion


        // Constructor
        public Mootor()
        {
            //Kõik muutujad default väärtusteks

            gameOver = true;
            gamePause = false;
            newGame = true;

            gameLines = 0;
            gameScore = 0;
            gameLevel = 0;


            timer = 0f;
            timerMax = INITIAL_TIMER_MAX;
        }


        public void CheckPausePlay(KeyboardState keyStateCurrent,
                                 KeyboardState keyStatePrevious,
                                  GamePadState padStateCurent,
                                  GamePadState padStatePrevious,
                                 Laud Laud,
                                 Klots Klots)
        {
            //See meetod läheb tööle kui vajutatakse P ehk pauset. Kui mäng on läbi
            //või algab siis vajutades P algab mäng. Kui mäng käib ning vajutatakse P
            //siis läheb mäng pause olekusse.

            if ((keyStateCurrent.IsKeyDown(Keys.P) && !keyStatePrevious.IsKeyDown(Keys.P)) ||
                (padStateCurent.IsButtonDown(Buttons.Start) && !padStatePrevious.IsButtonDown(Buttons.Start)))
            {

                if (gameOver)
                {
                    ResetVariablesNewGame(Laud, Klots);

                }
                else
                    gamePause = !gamePause;

            }
        }

        private void ResetVariablesNewGame(Laud Laud, Klots Klots)
        {
            // Resetime muutujad uueks mänguks
            gameOver = false;
            gamePause = false;
            newGame = false;
            gameLines = 0;
            gameScore = 0;
            gameLevel = 0;

            timer = 0f;
            timerMax = INITIAL_TIMER_MAX;

            // Loome mängulaua
            Laud.LooMangulaud();

            // Loome klotsid
            Klots.ResetBlock();
        }


        public void UpdateTimer(GameTime gameTime, Laud Laud, Klots Klots)
        {
            // Lisab timerile juurde, ning kontrollib, kas ta on läinud üle max aja
            // Kui nii juhtub, siis klots tuleb liigutada rea võrra alla või paigutada ruudustikus

            timer += (float)gameTime.ElapsedGameTime.TotalSeconds;

            if (timer >= timerMax)
            {
                timer = 0f;

                // Kutsub välja CollisionDetection(), et saada collisoni kohta infot
                CollisionDetection(Laud, Klots);

                if (Klots.BottomCollision)
                    PaigutaKlots(Laud, Klots);
                else
                    Klots.PositionRow += 1;
            }
        }


        public void CollisionDetection(Laud Laud, Klots Klots)
        {
            // Kui collisioni muutuja on true, siis see tähendab, et
            // klots mida liigutakse selles suunas läheks meie mängulaualt välja

            Klots.BottomCollision = false;
            Klots.LeftCollision = false;
            Klots.RightCollision = false;
            Klots.CwCollision = false;

            for (int row = 0; row < 4; row++)
                for (int col = 0; col < 4; col++)
                {
                    // Testime collisionit
                    if (Klots.KLOTSID[Klots.Klotstyyp, Klots.Asend, row, col] == 1)
                    {
                        int r = Klots.PositionRow + row;
                        int c = Klots.PositionCol + col;

                        // Vasakpoolne
                        if (c == 0)
                            Klots.LeftCollision = true;

                        if (c > 0 && Laud.GameGrid[r, c - 1] != -1)
                            Klots.LeftCollision = true;

                        // Parempoolne
                        if (c == Laud.ruudustiku_laius - 1)
                            Klots.RightCollision = true;

                        if (c < Laud.ruudustiku_laius - 1 && Laud.GameGrid[r, c + 1] != -1)
                            Klots.RightCollision = true;

                        // Alumine
                        if (r == Laud.ruudustiku_korgus - 1)
                            Klots.BottomCollision = true;

                        if (r < Laud.ruudustiku_korgus - 1 && Laud.GameGrid[r + 1, c] != -1)
                            Klots.BottomCollision = true;
                    }

                    // Testime kella suunas pööramise collisionit
                    int cwRotation = (Klots.Asend + 3) % 4;
                    if (Klots.KLOTSID[Klots.Klotstyyp, cwRotation, row, col] == 1)
                    {
                        int r = Klots.PositionRow + row;
                        int c = Klots.PositionCol + col;

                        if (r < 0 || r >= Laud.ruudustiku_korgus || c < 0 || c >= Laud.ruudustiku_laius)
                            Klots.CwCollision = true;
                        else if (Laud.GameGrid[r, c] != -1)
                            Klots.CwCollision = true;
                    }

                }
        }


        public void PaigutaKlots(Laud Laud, Klots Klots)
        {
            // See meetod kutsutakse välja kui klots ei saa enam liikuda
            // alla poole ning aeg sai otsa

            // Lisab klotsi möngulaua osaks
            Laud.LisaKlotsLauale(Klots);

            // Sätib järgise tuleva klotsi, tulevaks klotsiks

            Klots.VotaJargmineKlots();

            // Kontrollib, kas uus tulev klots ei põrkaks kohe mängulaual millegagi kokku
            KontolliManguLoppu(Laud, Klots);
        }


        public void KontolliManguLoppu(Laud Laud, Klots Klots)
        {
            // Mäng lõppeb, kui tulevale klotsile ei ole enam mängulaual ruumi

            for (int row = 0; row < 4; row++)
                for (int col = 0; col < 4; col++)
                    if (Klots.KLOTSID[Klots.Klotstyyp, Klots.Asend, row, col] == 1)
                        if (Laud.GameGrid[Klots.PositionRow + row, Klots.PositionCol + col] != -1)
                            gameOver = true;



        }

        public void xboxcontroller(GamePadState padStateCurrent,
                            GamePadState padStatePrevious,
                            Laud Laud,
                            Klots Klots)
        {
            CollisionDetection(Laud, Klots);

            // Paremale kangiga
            if (padStateCurrent.IsButtonDown(Buttons.LeftThumbstickRight) && !padStatePrevious.IsButtonDown(Buttons.LeftThumbstickRight)
                                                      && !Klots.RightCollision)
            {
                Klots.PositionCol += 1;
            }

            // Vasakule kangiga
            if (padStateCurrent.IsButtonDown(Buttons.LeftThumbstickLeft) && !padStatePrevious.IsButtonDown(Buttons.LeftThumbstickLeft)
                                                     && !Klots.LeftCollision)
            {
                Klots.PositionCol -= 1;

            }



            // Kang ülesse
            if (padStateCurrent.IsButtonDown(Buttons.LeftThumbstickUp) && !padStatePrevious.IsButtonDown(Buttons.LeftThumbstickUp)
                                                   && !Klots.CwCollision)
            {
                Klots.Asend = (Klots.Asend + 3) % 4;

            }

            // Kang alla
            if (padStateCurrent.IsButtonDown(Buttons.LeftThumbstickDown) && padStatePrevious.IsButtonDown(Buttons.LeftThumbstickDown)
                                                     && !Klots.BottomCollision)
            {
                Klots.PositionRow += 1;

            }

        }

        public void ProcessKeyboard(KeyboardState keyStateCurrent,
                                    KeyboardState keyStatePrevious,
                                    Laud Laud,
                                    Klots Klots)
        {
            // Saab klaviatuuri sisendi kasutajalt ja kontrollib kas see käsk on võimalik ning teeb seda

            // Esmalt kutsutakse välja CollisionDetection(), et näha mis liikumised on võimalikud
            CollisionDetection(Laud, Klots);

            // paremale
            if (keyStateCurrent.IsKeyDown(Keys.Right) && !keyStatePrevious.IsKeyDown(Keys.Right)
                                                      && !Klots.RightCollision)
            {
                Klots.PositionCol += 1;

            }

            // vasakule
            if (keyStateCurrent.IsKeyDown(Keys.Left) && !keyStatePrevious.IsKeyDown(Keys.Left)
                                                     && !Klots.LeftCollision)
            {
                Klots.PositionCol -= 1;

            }

            // ülesse
            if (keyStateCurrent.IsKeyDown(Keys.Up) && !keyStatePrevious.IsKeyDown(Keys.Up)
                                                   && !Klots.CwCollision)
            {
                Klots.Asend = (Klots.Asend + 3) % 4;

            }

            // alla
            if (keyStateCurrent.IsKeyDown(Keys.Down) && keyStatePrevious.IsKeyDown(Keys.Down)
                                                     && !Klots.BottomCollision)
            {
                Klots.PositionRow += 1;

            }
        }


        public void ManguLoogika(Laud Laud)
        {
            // Otsib täis ridu ning lisab ridade arvule otsa kui leiab mõne.
            int numLines = Laud.KontrolliTaisRida();

            // Tekib skoor vastavalt ridade ära kadumisele
            UuendaSkoori(numLines);

            // Igas järgmises levelis liigubad klotsid 0.2 sekundit kiiremine allapoole kui eelmises levelis
            UpdateTimerMax();

            // Iga 10 täis rea järel tõstetakse levelit 1 võrra
            UuendaLevelit();
        }


        public void UuendaSkoori(int numLines)
        {

            // uuenda kogu täisridade arvu summat
            gameLines += numLines;

            // Uuenda mänguskoori
            switch (numLines)
            {
                case 0:
                    break;

                case 1:
                    gameScore += 100;
                    break;

                case 2:
                    gameScore += 500;
                    break;

                case 3:
                    gameScore += 1000;
                    break;

                case 4:
                    gameScore += 2000;
                    break;
            }
        }


        public void UpdateTimerMax()
        {
            // See meetod teeb aega lühemaks, mille ajal klots ripub õhus, ennem kui ta liigub alla 1 ruudu võrra

            if (gameLevel < LAST_LEVEL_FOR_TIMER_DECREMENT)
                timerMax = INITIAL_TIMER_MAX - gameLevel * TIMER_DECREMENT;
            else
                timerMax = INITIAL_TIMER_MAX - LAST_LEVEL_FOR_TIMER_DECREMENT * TIMER_DECREMENT;
        }


        public void UuendaLevelit()
        {
            // Iga 10 täisrea järel läheb levelile 1 otsa

            gameLevel = (int)(gameLines / LINES_FOR_NEXT_LEVEL);
        }


        // ************ Joonistamise meetodid ******************


        public void JoonistaSkoor(SpriteFont gameFont, SpriteBatch spriteBatch)
        {
            // Joonista mängu statistika

            spriteBatch.Begin();

            Vector2 levelBoxSize = gameFont.MeasureString(gameLevel.ToString());
            spriteBatch.DrawString(gameFont, gameLevel.ToString(), LEVEL_BOX_CENTER - 0.5f * levelBoxSize, Color.Black);

            Vector2 linesBoxSize = gameFont.MeasureString(gameLines.ToString());
            spriteBatch.DrawString(gameFont, gameLines.ToString(), LINES_BOX_CENTER - 0.5f * linesBoxSize, Color.Black);

            Vector2 scoreBoxSize = gameFont.MeasureString(gameScore.ToString());
            spriteBatch.DrawString(gameFont, gameScore.ToString(), SCORE_BOX_CENTER - 0.5f * scoreBoxSize, Color.Black);

            spriteBatch.End();
        }

        public void JoonistaTulemus(SpriteFont gameFont, SpriteBatch spriteBatch)
        {
            // Joonista mängu tulemus

            spriteBatch.Begin();

            
            spriteBatch.DrawString(gameFont, gameScore.ToString(), new Vector2(470,430), Color.Black);

            spriteBatch.End();
        }

        public void JoonistaManguEkraan(Texture2D texture, SpriteBatch spriteBatch)
        {
            // See meetod joonistab menüü ja mänguekraani
            spriteBatch.Begin();
            spriteBatch.Draw(texture, Vector2.Zero, Color.White);
            spriteBatch.End();
        }


        public void JoonistaKoikKlotsid(Laud Laud, Klots Klots, SpriteBatch spriteBatch, SpriteFont spriteFont)
        {
            // Joonista antud klots, järgmine klots ning kõik paigutatud klotsid mängulaual

            Klots.JoonistaKlots(spriteBatch);
            Klots.JoonistaJargmineKlots(spriteBatch);
            Laud.JoonistaPaigutatudKlotsid(spriteBatch);
        }


        public static Vector2 GameCoorToScreenVec(int row, int col)
        {
            // See meetod konventeerib (rea, tulba) asukoha mängulaual
            //Vector2'ks
            Vector2 result;
            result.X = col * Klots.tyki_suurus;
            result.Y = row * Klots.tyki_suurus;

            return result;
        }

    }
}
